package com.colorsstudio.defence.Levels
{
	import com.colorsstudio.defence.algorithm.AStarLine;
	import com.colorsstudio.defence.algorithm.Waypoint;
	import com.colorsstudio.defence.baseClass.Enemy;
	import com.colorsstudio.defence.baseClass.GUIClass;
	import com.colorsstudio.defence.baseClass.IPopUpWindow;
	import com.colorsstudio.defence.baseClass.Player;
	import com.colorsstudio.defence.baseClass.PopUpSettingWindow;
	import com.colorsstudio.defence.baseClass.Slide;
	import com.colorsstudio.defence.ConstantValues.Constants;
	import com.colorsstudio.defence.flashExportClass.f_btnStory;
	import com.colorsstudio.defence.flashExportClass.f_enemy1;
	import com.colorsstudio.defence.flashExportClass.f_enemy2;
	import com.colorsstudio.defence.flashExportClass.f_enemy3;
	import com.colorsstudio.defence.flashExportClass.f_enemy4;
	import com.colorsstudio.defence.flashExportClass.f_enemy5;
	import com.colorsstudio.defence.flashExportClass.f_enemy6;
	import com.colorsstudio.defence.flashExportClass.f_enemy7;
	import com.colorsstudio.defence.flashExportClass.f_enemy8;
	import com.colorsstudio.defence.flashExportClass.f_enemy9;
	import com.colorsstudio.defence.flashExportClass.f_towerG;
	import com.colorsstudio.defence.flashExportClass.f_towerR;
	import com.colorsstudio.defence.flashExportClass.f_towerY;
	import com.colorsstudio.defence.sounds.SoundLibrary;
	import com.colorsstudio.defence.sounds.SoundManager;
	import com.colorsstudio.defence.util.NumberUtilities;
	import com.colorsstudio.defence.util.singletonFactory1;
	import com.greensock.TweenMax;
	import de.polygonal.ds.Array2;
	import de.polygonal.ds.Graph;
	import de.polygonal.ds.GraphArc;
	import de.polygonal.ds.GraphNode;
	import de.polygonal.ds.LinkedQueue;
	import de.polygonal.ds.LinkedStack;
	import flash.display.Graphics;
	import flash.display.MovieClip;
	import flash.display.Shape;
	import flash.display.SimpleButton;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.text.TextField;
	import flash.utils.getDefinitionByName;
	import flash.utils.Timer;
	import idv.cjcat.fenofsm.events.StateEvent;
	import idv.cjcat.fenofsm.Transition;
	import idv.cjcat.signals.ISignal;
	import idv.cjcat.signals.Signal;
	
	/**
	 * ...
	 * @author wuzhida
	 */
	public class gameScene1 extends Level
	{
		//保存fsm状态；
		public var t_startScreen_gameScene1:Transition;
		public var t_gameScene1_startScreen:Transition;
		public var t_this_this:Transition;
		//保存backGround
		public var bg:Sprite;
		//add the grid , half alpha and half static
		public var gridSprite:Sprite;
		//这个其实是保存数组的长宽的，这个游戏我们是720*480  40*40的塔宽 所以是18和12
		public const numWidth:int = Constants.SCREEN_WIDTH / Constants.DEFENCER_WIDTH;
		public const numHeight:int = Constants.SCREEN_HEIGHT / Constants.DEFENCER_HEIGHT;
		public var defenceArray:Array2 = new Array2(numWidth, numHeight);
		
		//三个按钮
		public var btnTowerG:SimpleButton;
		public var btnTowerY:SimpleButton;
		public var btnTowerR:SimpleButton;
		
		//保存当前的塔的数组，currenTower保存点击按钮之后黏在鼠标上的那个tower
		public var arrayTower:Array = new Array();
		public var currentTower:MovieClip;
		
		/*这个就是那个地图的保存格式。
		   0、1、2、3、4、5、6、7、8、9、10、11、12、13、14、15
		   1 * 16+0、1 * 16 + 1、。。。。。。。。。。。。。。。。。
		   2 * 16+0、2 * 16 + 1、。。。。。。。。。。。。。。。。。
		   3 * 16+0、2 * 16 + 1、。。。。。。。。。。。。。。。。。
		   4 * 16+0、2 * 16 + 1、。。。。。。。。。。。。。。。。。
		   5 * 16+0、2 * 16 + 1、。。。。。。。。。。。。。。。。。
		   6 * 16+0、2 * 16 + 1、。。。。。。。。。。。。。。。。。
		   7 * 16+0、2 * 16 + 1、。。。。。。。。。。。。。。。。。
		   8 * 16+0、2 * 16 + 1、。。。。。。。。。。。。。。。。。
		 */
		//例如上面这个图，人物如果在0，那么0-1、0-16都是有边的，暂时还没考虑可不可以斜着走。
		//还有个问题，就是出入口需要另外设置，到时候只要特别加入出入口设置就行了。
		
		//数据结构---图
		public var graph:Graph;
		
		//图的节点个数
		public var nodeCount:int = 0;
		
		//使用linkQueue保存节点
		public var nodeQue:LinkedQueue;
		
		//测试的时候点开始、点结束的两个node
		public var startNode:GraphNode;
		public var endNode:GraphNode;
		public var startNodeIndex:int;
		public var endNodeIndex:int;
		
		//判断是否存在路径
		public var pathExists:Boolean;
		
		//使用stack来保存返回的结果，也就是当前的最短路是怎么走的，这个到时候我可能会放到敌人里面 。
		public var path:LinkedStack;
		public var timer:Timer = new Timer(2000, 1);
		
		//记录敌人个数和数组
		public var enemyCount:int = Constants.S1_ENEMY_COUNT;
		public var enemyArray:Array = new Array();
		public var currentEnemy:Enemy;
		
		//当对地图进行更新完毕时，再发送事件。最先发出消息的是塔放下的时候，然后通知gamescene1更新地图，然后enemy们都要更更行自己的路径。
		public var signalGraphResetComplete:ISignal = new Signal(int, int);
		
		//这个数组用于记录当前地图的状态，用来记录每一个格子是否已经被占有
		public var mapStatus:Array2 = new Array2(numWidth, numHeight);
		
		//记录
		public var Draw:Sprite = new Sprite();		
		//记录玩家的金钱、生命、时间、分数、是否在玩游戏（暂停）
		public var gui:GUIClass  = singletonFactory1(GUIClass);
		//声音
		public var soundManager:SoundManager = new SoundManager();
		public var SOUND_TEST_SOUND:String = "TestSound";
		//pauseGame , continueGame
		public var signalPauseGame:ISignal = new Signal();
		public var signalUnPauseGame:ISignal = new Signal();
		//the speed scale:
		public var speedScale:Number = 1;
		public var signalSpeedScale:ISignal = new Signal();
		//popUp windows:
		public var popUpSettingWindow:PopUpSettingWindow;
	
		
		public function gameScene1()
		{
			super();
		}
		
		//需要处理有限状态机fsm的状态迁移，所以需要在gameMain里面先new出来
		override public function setState():void
		{
			state = Constants.fsm.createState("gameScene1");
			t_startScreen_gameScene1 = Constants.fsm.createTransition(Constants.fsm.getStateByName("startScreen"), state, "toGameScene1", "t_startScreen_gameScene1", 0);
			t_gameScene1_startScreen = Constants.fsm.createTransition(state, Constants.fsm.getStateByName("startScreen"), "gameScene1BackToStartScreen", "t_gameScene1_startScreen", 0);
			t_this_this = Constants.fsm.createTransition(state, state, "tomyself", "t_this_this",0);
			super.setState();
		}
		
		//这个gameScene1在这里开始
		override public function levelStart(e:StateEvent):void
		{
			super.levelStart(e);
			Constants.main.addChild(this);
			thisLevelGosHere();
		}
		
		//这个是开始的函数，写出来好看点
		public function thisLevelGosHere():void
		{
			
			enemyCount = Constants.S1_ENEMY_COUNT;
			//设置player 信息,玩家每关的生命都是20，这个lastHealth是永远不更新的，但是score和money都需要一直玩下去的。
			gui.player.currentHealth = gui.player.lastHealth;
			gui.player.currentMoney = gui.player.lastMoney;
			gui.player.currentScore = gui.player.lastScore;
			gui.updateText();
			//设置引用，这个需要用到
			Constants.CURRENT_SCENE = this;
			//new一个popWindow
			popUpSettingWindow = new PopUpSettingWindow();
			soundManager.addSound(SOUND_TEST_SOUND, new SoundLibrary.TestSound);
			//soundManager.playSound(SOUND_TEST_SOUND, true, int.MAX_VALUE);			
			//添加Draw,remove it before end!
			this.stage.addChild(Draw);
			//add the gui signal , remove them before ends!
			this.layer4.addChild(gui);			
			gui.signalPause.add(muteSound);
			gui.signalSetting.add(dispLaySettingScene);
			gui.signalSpeedUp.add(speedUp);
			//we donot need to remove the bg,beacause the level super class remove it 
			bg = new f_bg();
			this.layer1.addChild(bg);			
			//添加透明的格子
			for (var i:int = 0; i < numWidth - 2; i++)
			{
				for (var j:int = 0; j < numHeight - 3; j++)
				{
					//所有蓝色的格子
					//t = new f_defencer1();
					//t.labelText.text = j + " , " + i;
					//TextField(t.labelText).selectable = false;
					//this.layer1.addChild(t);
					//t.x = Constants.DEFENCER_WIDTH * (i + 1);
					//t.y = Constants.DEFENCER_HEIGHT * (j + 1);
					//defenceArray.set(i, j, t);
					mapStatus.set(i, j, 0);
				}
			}
			
			//三个塔的按钮new出来
			btnTowerG = new f_btnTowerG();
			btnTowerG.x = 15 * Constants.DEFENCER_WIDTH;
			btnTowerG.y = 11 * Constants.DEFENCER_HEIGHT;
			this.layer4.addChild(btnTowerG);
			
			btnTowerR = new f_btnTowerR();
			btnTowerR.x = 16 * Constants.DEFENCER_WIDTH;
			btnTowerR.y = 11 * Constants.DEFENCER_HEIGHT;
			this.layer4.addChild(btnTowerR);
			
			btnTowerY = new f_btnTowerY();
			btnTowerY.x = 17 * Constants.DEFENCER_WIDTH;
			btnTowerY.y = 11 * Constants.DEFENCER_HEIGHT;
			this.layer4.addChild(btnTowerY);
			
			//添加按钮事件
			btnTowerY.addEventListener(MouseEvent.CLICK, clickTowerY,false,0,true);
			btnTowerG.addEventListener(MouseEvent.CLICK, clickTowerG,false,0,true);
			btnTowerR.addEventListener(MouseEvent.CLICK, clickTowerR,false,0,true);
			
			//处理图
			//=================================================================================
			//=================================================================================
			//处理那些小圈圈，处理图，同时处理那些计算最短路的算法。
			//new一个一百个node 的图，坑爹 啊，后来发现100个根本就不对！至少要144个，害我调试半天。
			graph = new Graph(200);
			
			//为这个图添加node，这里的node是wayPoint
			for (var w:int = 0; w < numWidth - 2; w++)
			{
				for (var h:int = 0; h < numHeight - 3; h++)
				{
					var wp:Waypoint = new Waypoint(h * 16 + w);
					wp.setPos(Constants.DEFENCER_WIDTH * (w + 1), Constants.DEFENCER_HEIGHT * (h + 1));
					graph.addNode(wp, h * 16 + w);
				}
			}
			
			//为这些waypoint添加Arc，也就是边，这个不可以和node一起做，因为有时候还没node就添加边就会出错
			for (var k:int = 0; k < numHeight - 3; k++)
			{
				for (var l:int = 0; l < numWidth - 2; l++)
				{
					//每个点都有四个方向：
					if (l > 0)
					{
						graph.addArc(l + k * 16, l - 1 + k * 16, 1);
					}
					if (l < 15)
					{
						graph.addArc(l + k * 16, l + 1 + k * 16, 1);
					}
					if (k > 0)
					{
						graph.addArc(l + k * 16, l + (k - 1) * 16, 1);
					}
					if (k < 8)
					{
						graph.addArc(l + k * 16, l + (k + 1) * 16, 1);
					}
				}
			}
			//硬性写了startNodeIndex，本来是想放在constants里面的，因为以后换成iphone估计会有调整。
			startNodeIndex = Constants.S1_ST_NODE_X + Constants.GRID_WIDTH * Constants.S1_ST_NODE_Y;
			endNodeIndex = Constants.S1_EN_NODE_X +Constants.GRID_WIDTH * Constants.S1_EN_NODE_Y;
			//获得图的开始节点和结束节点。
			startNode = graph.nodes[startNodeIndex];
			endNode = graph.nodes[endNodeIndex];
			//判断是否有路径
			pathExists = AStarLine.find(graph, startNode, endNode);
			if (!pathExists)
			{
				trace("A HA, the path is not exists!");
				return;
			}
			
			//now path contains a stack of waypoints, popping waypoints off
			//the stack goes from start to goal.
			path = AStarLine.getPath(startNode, endNode);
			//trace(path.dump());
			
			//每隔一段时间出敌人。
			//这个需要在每关dispose里面stop 和remove
			timer = new Timer(Constants.S1_ENEMY_INTERVAL, enemyCount);
			timer.addEventListener(TimerEvent.TIMER, animate,false,0,true);
			timer.addEventListener(TimerEvent.TIMER_COMPLETE, onAnimationComplete,false,0,true);
			timer.start();
			
			//=================================================================================
			//=================================================================================
			//处理图
			
			draw();
		}
		
		public function speedUp(num:Number):void
		{
			trace("speedUpGGG");
			timer.stop();
			timer.removeEventListener(TimerEvent.TIMER, animate,false);
			timer.removeEventListener(TimerEvent.TIMER_COMPLETE, onAnimationComplete,false);
			var c:int = timer.currentCount;
			enemyCount -= c;			
			var t:int = 1000 / num;
			timer  = new Timer(t, enemyCount);
			timer.addEventListener(TimerEvent.TIMER, animate,false,0,true);
			timer.addEventListener(TimerEvent.TIMER_COMPLETE, onAnimationComplete,false,0,true);
			timer.start();
		}
		
		override public function pauseGame():void
		{
			if (timer == null) return;
			if (!flag)
			{
				timer.stop();
				signalPauseGame.dispatch();
				flag = !flag;
			}
			else
			{
				timer.start();
				signalUnPauseGame.dispatch();
				flag = !flag;
			}
		}
		
		public function dispLaySettingScene():void 
		{
			pauseGame();
		}
		
		public function muteSound():void 
		{			
			this.layer4.addChild(popUpSettingWindow);	
			if (!flag)
			{
				pauseGame();
			}
		}
		
		private function onAnimationComplete(e:Event):void
		{
			timer.stop();
			timer.removeEventListener(TimerEvent.TIMER, animate,false);
			timer.removeEventListener(TimerEvent.TIMER_COMPLETE, onAnimationComplete, false);
		}
		
		private function animate(e:Event):void
		{
			switch (NumberUtilities.random(1, 9, 1))
			{
				case 1: 
					currentEnemy = new f_enemy1(startNodeIndex, endNodeIndex, graph, 100);
					break;
				case 2: 
					currentEnemy = new f_enemy2(startNodeIndex, endNodeIndex, graph, 200);
					break;
				case 3: 
					currentEnemy = new f_enemy3(startNodeIndex, endNodeIndex, graph, 300);
					break;
				case 4: 
					currentEnemy = new f_enemy4(startNodeIndex, endNodeIndex, graph, 400);
					break;
				case 5: 
					currentEnemy = new f_enemy5(startNodeIndex, endNodeIndex, graph, 500);
					break;
				case 6: 
					currentEnemy = new f_enemy6(startNodeIndex, endNodeIndex, graph, 600);
					break;
				case 7: 
					currentEnemy = new f_enemy7(startNodeIndex, endNodeIndex, graph, 700);
					break;
				case 8: 
					currentEnemy = new f_enemy8(startNodeIndex, endNodeIndex, graph, 800);
					break;
				case 9: 
					currentEnemy = new f_enemy9(startNodeIndex, endNodeIndex, graph, 900);
					break;
				default: 
			}
			
			currentEnemy.x = Constants.DEFENCER_WIDTH * (startNodeIndex % 16 + 1) + 20;
			currentEnemy.y = Constants.DEFENCER_HEIGHT * (startNodeIndex / 16 + 1) + 20;
			this.layer2.addChild(currentEnemy);
			enemyArray.push(currentEnemy);
			currentEnemy.animate();
			signalGraphResetComplete.add(currentEnemy.reAnimate);
			currentEnemy.signalFleet.add(gui.updateText);
			signalPauseGame.add(currentEnemy.pause);
			signalUnPauseGame.add(currentEnemy.unPause);
			gui.signalSpeedUp.add(currentEnemy.speedUp);
		}
		
		//处理红色按钮，每次按下都new出来一个塔：
		private function clickTowerR(e:MouseEvent):void
		{
			currentTower = new f_towerR(btnTowerY.x, btnTowerY.y);
			this.layer3.addChild(currentTower);
			arrayTower.push(currentTower);
			currentTower.signalTowerPlace.add(resetGraph);
			currentTower.signalEnemyKill.add(gui.updateText);
			signalPauseGame.add(currentTower.pause);
			signalUnPauseGame.add(currentTower.unPause);
			gui.signalSpeedUp.add(currentTower.speedUp);
		}
		
		//处理绿色按钮，每次按下都new出来一个塔：
		private function clickTowerG(e:MouseEvent):void
		{
			currentTower = new f_towerG(btnTowerY.x, btnTowerY.y);
			this.layer3.addChild(currentTower);
			arrayTower.push(currentTower);
			currentTower.signalTowerPlace.add(resetGraph);
			currentTower.signalEnemyKill.add(gui.updateText);
			signalPauseGame.add(currentTower.pause);
			signalUnPauseGame.add(currentTower.unPause);
			gui.signalSpeedUp.add(currentTower.speedUp);
		}
		
		//处理黄色按钮，每次按下都new出来一个塔：
		private function clickTowerY(e:MouseEvent):void
		{
			currentTower = new f_towerY(btnTowerY.x, btnTowerY.y);
			this.layer3.addChild(currentTower);
			arrayTower.push(currentTower);
			currentTower.signalTowerPlace.add(resetGraph);
			currentTower.signalEnemyKill.add(gui.updateText);
			signalPauseGame.add(currentTower.pause);
			signalUnPauseGame.add(currentTower.unPause);
			gui.signalSpeedUp.add(currentTower.speedUp);
		}
		
		//这是重新刷新地图的arc和node
		public function resetGraph(gridX:int, gridY:int):void
		{
			
			draw();
			
			//发送事件给不同enemy
			signalGraphResetComplete.dispatch(gridX, gridY * 16);
		}
		
		//关卡在这里结束
		override public function levelEnd(e:StateEvent):void
		{
			super.levelEnd(e);			
		}
		
		//画线
		public function draw():void
		{
			Draw.graphics.clear();
			Draw.graphics.lineStyle(1.3, 0x000000, .7);
			
			//draw all arcs originating from the given node
			for (var i:int = 0; i < graph.nodes.length; i++)
			{
				if (graph.nodes[i])
					graph.breadthFirst(graph.nodes[i], drawNodeArcs);
			}
		}
		
		public function drawNodeArcs(node:GraphNode, target:GraphNode = null):void
		{
			var arcStart:Waypoint = node.data;
			
			for (var i:int = 0; i < node.numArcs; i++)
			{
				var arc:GraphArc = node.arcs[i];
				var arcTarget:Waypoint = arc.node.data;
				
				if (target && arc.node != target)
					continue;
				var dx:Number = arcTarget.x - arcStart.x;
				var dy:Number = arcTarget.y - arcStart.y;
				var len:Number = Math.sqrt(dx * dx + dy * dy);
				
				var xdir:Number = dx / len;
				var ydir:Number = dy / len;
				
				if (len < 30)
				{
					Draw.graphics.moveTo(arcStart.x + xdir * (4), arcStart.y + ydir * (4));
					Draw.graphics.lineTo(arcTarget.x - xdir * (4), arcTarget.y - ydir * (4));
				}
				else
					drawArrow(Draw.graphics, arcStart.x + Constants.DEFENCER_WIDTH / 2 + xdir * (4), arcStart.y + Constants.DEFENCER_HEIGHT / 2 + ydir * (4), xdir, ydir, len - 2 * (4), 4);
			}
		}
		
		public function drawArrow(g:Graphics, x:Number, y:Number, xdir:Number, ydir:Number, len:Number, size:Number):void
		{
			var t:Number = 1 / Math.sqrt(xdir * xdir + ydir * ydir);
			
			var ex:Number = (xdir * t * len) + x;
			var ey:Number = (ydir * t * len) + y;
			
			g.moveTo(x, y);
			g.lineTo(ex, ey);
			
			var dx:Number = (ex - x);
			var dy:Number = (ey - y);
			
			var l:Number = Math.sqrt((dx * dx) + (dy * dy));
			if (l <= 0)
				return;
			
			dx /= l;
			dy /= l;
			var nx:Number = -dy;
			var ny:Number = dx;
			g.moveTo(ex, ey);
			g.lineTo((ex - (size * dx)) - (size * nx), (ey - (size * dy)) - (size * ny));
			g.moveTo(ex, ey);
			g.lineTo((ex - (size * dx)) + (size * nx), (ey - (size * dy)) + (size * ny));
		}
		
		override public function restartGame():void 
		{
			super.restartGame();
			Constants.fsm.input("tomyself");
			trace("fsm.input to gamescene 1");
		}
		
		override public function mainMenu():void 
		{
			super.mainMenu();
			Constants.fsm.input("gameScene1BackToStartScreen");
			trace("fsm.input to startScreen");
		}
		
		override public function dispose():void 
		{		
			Draw.graphics.clear();
			this.stage.removeChild(Draw);
			if (timer.running)
			{
				timer.removeEventListener(TimerEvent.TIMER, animate,false);
				timer.removeEventListener(TimerEvent.TIMER_COMPLETE, onAnimationComplete,false);
			}
			super.dispose();
			Constants.main.removeChild(this);	
			TweenMax.killAll();
		}
	}
}